import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

/**
 * 需求：手机网购App的界面，每一件商品都有描述图片，部分商品描述图片是相同的，再加载一遍会浪费大量时间和资源。
 * 同时因为没有本地缓存，每次打开应用需要重新加载，非常浪费资源。
 */
public class Main {
  public static void main(String[] args) {
    ImagePool imagePool = new ImagePool();
    Image image = imagePool.getImage("123456");
    System.out.println(image);
    image = imagePool.getImage("123456");
    image = imagePool.getImage("123456");
    image = imagePool.getImage("876543");
  }
}

class ImagePool {
  // 每张图片有三个状态：未加载、加载中、已加载
  // 目前先实现"未加载"和"已加载"两个功能。
  // "已加载"又分为"加载到本地存储"与"加载到内存"

  Map<String, Image> buffer = new HashMap<>();

  public Image getImage(String checksum) {
    Image result = null;
    result = getImageFromBuffer(checksum);
    if (result == null)
      result = getImageFromLocalStorage(checksum);
    if (result == null)
      result = getImageFromServer(checksum);
    return result;
  }

  private Image getImageFromServer(String checksum) {
    System.out.println("Got image from server");
    Image result =
        new Image(checksum, "Image{" + checksum + "}"); // Pretend to have everything on server
    storeInBuffer(checksum, result);
    storeLocally(checksum, result);
    return result;
  }

  private Image getImageFromLocalStorage(String checksum) {
    Image result = null;
    try (InputStream input = new FileInputStream("images/" + checksum)) {
      result = new Image(checksum, new String(input.readAllBytes()));
    } catch (Exception e) {
      result = null;
    }
    if (result != null) {
      System.out.println("Got image from local storage");
      storeInBuffer(checksum, result);
    }
    return result;
  }

  private Image getImageFromBuffer(String checksum) {
    Image result = null;
    result = buffer.get(checksum);
    if (result != null) {
      System.out.println("Got image from buffer");
    }
    return result;
  }

  private void storeInBuffer(String checksum, Image image) {
    buffer.put(checksum, image);
  }

  private void storeLocally(String checksum, Image image) {
    try (Writer output = new FileWriter("images/" + checksum)) {
      output.write(image.content);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

class Image {
  public String checksum;
  public String content;
  Image(String checksum, String content) {
    this.checksum = checksum;
    this.content = content;
  }

  @Override
  public String toString() {
    return content;
  }
}